home *** CD-ROM | disk | FTP | other *** search
- /*
- * POP2 Client routines. Originally authored by Mike Stockett
- * (WA7DYX).
- * Modified 12 May 1991 by Mark Edwards (WA6SMN) to use new timer
- * facilities in NOS0423. Fixed type mismatches spotted by C++.
- * Modified 27 May 1990 by Allen Gwinn (N5CKP) for compatibility
- * with later releases (NOS0522).
- * Added into NOS by PA0GRI (and linted into "standard" C)
- *
- * Some code culled from previous releases of SMTP.
- *
- * Client routines for Simple Mail Transfer Protocol ala RFC821
- * A.D. Barksdale Garbee II, aka Bdale, N3EUA
- * Copyright 1986 Bdale Garbee, All Rights Reserved.
- * Permission granted for non-commercial copying and use, provided
- * this notice is retained.
- * Modified 14 June 1987 by P. Karn for symbolic target addresses,
- * also rebuilt locking mechanism
- * Copyright 1987 1988 David Trulli, All Rights Reserved.
- * Permission granted for non-commercial copying and use, provided
- * this notice is retained.
- */
- #include "global.h"
- #ifdef POP
- #ifndef MSDOS
- #include <setjmp.h>
- #include <stdarg.h>
- #include "mbuf.h"
- #include "proc.h"
- #include "socket.h"
- #endif
- #include "hardware.h"
- #include "cmdparse.h"
- #include "netuser.h"
- #include "files.h"
- #include "mailutil.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: popcli.c,v 1.17 1997/09/07 21:18:28 root Exp root $";
- #endif
-
- #define BUF_LEN 257
-
- /* POP client control block */
-
- struct pop_ccb {
- int socket; /* socket for this connection */
- char state; /* client state */
- #define CALL 0
- #define NMBR 3
- #define SIZE 5
- #define XFER 8
- #define EXIT 10
- char buf[BUF_LEN]; /* tcp input buffer */
- int folder_len; /* number of msgs in current folder */
- long msg_len; /* length of current msg */
- int msg_num; /* current message number */
- };
- static struct pop_ccb *ccb;
-
- #define NULLCCB (struct pop_ccb *)0
-
- static int Popquiet = 0;
-
- static struct timer popcli_t;
- static uint32 mailhost;
- static char mailbox_name[10], mailbox_pathname[BUF_LEN], username[20],
- password[20], Workfile_name[] = "mbox.pop";
-
- static int domailbox (int argc, char *argv[], void *p);
- static int domailhost (int argc, char *argv[], void *p);
- static int douserdata (int argc, char *argv[], void *p);
- static int doquiet (int argc, char *argv[], void *p);
- static int dotimer (int argc, char *argv[], void *p);
- static struct pop_ccb *new_ccb (void);
- static void delete_ccb (void);
- static void pop_send (int unused, void *cb1, void *p);
- static int popkick (int argc, char *argv[], void *p);
- int dopop (int argc, char *argv[], void *p);
- static void pop_csm (struct pop_ccb * theccb);
- static void quit_session (struct pop_ccb * theccb);
- extern void rrip (register char *s);
-
- /* I don't know why this isn't static, it isn't called anywhere else {was} */
- static int poptick (void);
-
- static struct cmds Popcmds[] =
- {
- { "mailbox", domailbox, 0, 0, NULLCHAR },
- { "mailhost", domailhost, 0, 0, NULLCHAR },
- { "kick", popkick, 0, 0, NULLCHAR },
- { "quiet", doquiet, 0, 0, NULLCHAR },
- { "timer", dotimer, 0, 0, NULLCHAR },
- { "userdata", douserdata, 0, 0, NULLCHAR },
- { NULLCHAR, 0, 0, 0, NULLCHAR }
- };
-
-
- /* Command string specifications */
-
- static char ackd_cmd[] = "ACKD\n";
- static char login_cmd[] = "HELO %s %s\n";
- static char quit_cmd[] = "QUIT\n";
- static char read_cur_cmd[] = "READ\n";
- static char retr_cmd[] = "RETR\n";
- static const char *greeting_rsp = "+ POP2 ";
-
- #ifdef POP_FOLDERS
- static char fold_cmd[] = "FOLD %s\n";
- #endif
- #if 0
- static char nack_cmd[] = "NACK\n"; /* Not implemented */
- #endif
-
-
- static FILE *fd;
-
-
-
- int
- dopop (int argc, char *argv[], void *p)
- {
- return subcmd (Popcmds, argc, argv, p);
- }
-
-
-
- static int
- domailbox (int argc, char *argv[], void *p OPTIONAL)
- {
- if (argc < 2) {
- if (mailbox_name[0] == '\0')
- tputs ("mailbox name not set yet\n");
- else
- tprintf ("%s\n", mailbox_name);
- } else
- strncpy (mailbox_name, argv[1], 10);
-
- return 0;
- }
-
-
-
- static int
- domailhost (int argc, char *argv[], void *p OPTIONAL)
- {
- uint32 n;
-
- if (argc < 2)
- tprintf ("%s\n", inet_ntoa (mailhost));
- else if ((n = resolve (argv[1])) == 0) {
- tprintf (Badhost, argv[1]);
- return 1;
- } else
- mailhost = n;
-
- return 0;
- }
-
-
-
- static int
- doquiet (int argc, char *argv[], void *p OPTIONAL)
- {
- return setbool (&Popquiet, "POP quiet", argc, argv);
- }
-
-
-
- static int
- douserdata (int argc, char *argv[], void *p OPTIONAL)
- {
- if (argc < 2)
- tprintf ("%s\n", username);
- else if (argc != 3) {
- tputs ("Usage: pop userdata <username> <password>\n");
- return 1;
- } else {
- sscanf (argv[1], "%18s", username);
- sscanf (argv[2], "%18s", password);
- }
-
- return 0;
- }
-
-
-
- /* Set scan interval */
-
- static int
- dotimer (int argc, char *argv[], void *p OPTIONAL)
- {
- if (argc < 2) {
- tprintf ("%lu/%lu\n", read_timer (&popcli_t) / 1000L, dur_timer (&popcli_t) / 1000L);
- return 0;
- }
- popcli_t.func = (void (*)(void *)) poptick; /* what to call on timeout */
- popcli_t.arg = NULL; /* dummy value */
- set_timer (&popcli_t, atol (argv[1]) * 1000L); /* set timer duration */
- start_detached_timer (&popcli_t);/* and fire it up */
- return 0;
- }
-
-
-
- static int
- popkick (int argc OPTIONAL, char *argv[]OPTIONAL, void *p OPTIONAL)
- {
- (void) poptick ();
- return 0;
- }
-
-
-
- static int
- poptick ()
- {
- if (ccb == NULLCCB) {
- /* Don't start if any of the required parameters have not been specified */
-
- if (mailhost == 0) {
- tputs ("mailhost not defined yet.(pop mailhost <host>)\n");
- return 0;
- }
- if (mailbox_name[0] == '\0') {
- tputs ("mailbox name not defined yet.(pop mailbox <name>)\n");
- return 0;
- }
- if (username[0] == '\0') {
- tputs ("username not defined yet. (pop user <name> <pass>)\n");
- return 0;
- }
- if (password[0] == '\0') {
- tputs (" Unknown password\n");
- return 0;
- }
- if ((ccb = new_ccb ()) == NULLCCB) {
- tcmdprintf ("*** Unable to allocate CCB\n");
- return 0;
- }
- (void) newproc ("Auto-POP Client", 1024, pop_send, 0, ccb, NULL, 0);
- }
- /* Restart timer */
-
- start_detached_timer (&popcli_t);
- return 0;
- }
-
-
-
- /* this is the master state machine that handles a single SMTP transaction */
- /* it is called with a queue of jobs for a particular host. */
-
- static void
- pop_send (int unused OPTIONAL, void *cb1, void *p OPTIONAL)
- {
- char const *cp;
- struct sockaddr_in fsocket;
- struct pop_ccb *theccb;
-
- theccb = (struct pop_ccb *) cb1;
- fsocket.sin_family = AF_INET;
- fsocket.sin_addr.s_addr = mailhost;
- fsocket.sin_port = IPPORT_POP;
-
- theccb->socket = socket (AF_INET, SOCK_STREAM, 0);
-
- theccb->state = CALL;
-
- if (connect (theccb->socket, (char *) &fsocket, SOCKSIZE) == 0)
- log (theccb->socket, "Connected to mailhost %s", inet_ntoa (mailhost));
- else {
- cp = sockerr (theccb->socket);
- log (theccb->socket, "Connect to mailhost %s failed: %s", inet_ntoa (mailhost),
- (cp != NULLCHAR) ? cp : "");
- }
-
- for (;;) {
- if (recvline (theccb->socket, (unsigned char *) theccb->buf, BUF_LEN) == -1)
- break;
-
- rrip (theccb->buf);
- pop_csm (theccb);
- if (theccb->state == EXIT)
- break;
- }
-
- log (theccb->socket, "Connection closed to mailhost %s", inet_ntoa (mailhost));
- close_s (theccb->socket);
- if (fd != NULLFILE)
- fclose (fd);
- delete_ccb ();
- }
-
-
-
- /* free the message struct and data */
-
- static void
- delete_ccb ()
- {
- if (ccb == NULLCCB)
- return;
-
- free ((char *) ccb);
- ccb = NULLCCB;
- }
-
-
-
- /* create a new pop control block */
-
- static struct pop_ccb *
- new_ccb ()
- {
- register struct pop_ccb *theccb;
-
- if ((theccb = (struct pop_ccb *) callocw (1, sizeof (struct pop_ccb))) == NULLCCB)
- return (NULLCCB);
-
- return (theccb);
- }
-
-
-
- /* ---------------------- pop client code starts here --------------------- */
-
- static void
- pop_csm (struct pop_ccb *theccb)
- {
- FILE *mf;
-
- switch (theccb->state) {
- case CALL:
- if (strncmp (theccb->buf, greeting_rsp, strlen (greeting_rsp)) == 0) {
- (void) usprintf (theccb->socket, login_cmd, username, password);
- theccb->state = NMBR;
- } else
- quit_session (theccb);
- break;
-
- case NMBR:
- switch (theccb->buf[0]) {
- case '#':
- if ((fd = fopen (Workfile_name, "a+")) == NULLFILE) {
- perror ("Unable to open work file");
- quit_session (theccb);
- return;
- }
- fseek (fd, 0, SEEK_SET);
- theccb->folder_len = atoi (&(theccb->buf[1]));
- (void) usprintf (theccb->socket, read_cur_cmd);
- theccb->state = SIZE;
- break;
-
- case '+':
-
- /* If there is no mail (the only time we get a "+"
- * response back at this stage of the game),
- * then just close out the connection, because
- * there is nothing more to do!! */
-
- default:
- quit_session (theccb);
- break;
- }
- break;
-
- case SIZE:
- if (theccb->buf[0] == '=') {
- theccb->msg_len = atol (&(theccb->buf[1]));
- if (theccb->msg_len > 0) {
- (void) usprintf (theccb->socket, retr_cmd);
- theccb->state = XFER;
- } else {
- log (theccb->socket, "POP client retrieved %d messages",
- theccb->folder_len);
-
- /* All done, so do local cleanup */
-
- if (mlock (Mailspool, mailbox_name)) {
- tprintf ("\n*** Local mailbox locked, new mail in file %s\n", Workfile_name);
- quit_session (theccb);
- return;
- }
- sprintf (mailbox_pathname, "%s/%s.txt", Mailspool, mailbox_name);
- if ((mf = fopen (mailbox_pathname, "a+")) == NULL) {
- tprintf ("\n*** Unable to open local mailbox, new mail in file %s\n", Workfile_name);
- quit_session (theccb);
- return;
- }
- fseek (fd, 0, SEEK_SET);
-
- while (!feof (fd)) {
- if (fgets (theccb->buf, BUF_LEN, fd) != NULLCHAR)
- fputs (theccb->buf, mf);
- }
- fclose (mf);
- fclose (fd);
- fd = NULL;
- tprintf ("New mail arrived for %s from mailhost <%s>%c\n",
- mailbox_name, inet_ntoa (mailhost), Popquiet ? ' ' : '\007');
- rmlock (Mailspool, mailbox_name);
- unlink (Workfile_name);
- quit_session (theccb);
- }
- } else
- quit_session (theccb);
- break;
-
- case XFER:
- fprintf (fd, "%s\n", theccb->buf);
-
- theccb->msg_len -= (long) (strlen (theccb->buf) + 2); /* Add CRLF */
-
- if (theccb->msg_len > 0)
- return;
-
- (void) usprintf (theccb->socket, ackd_cmd);
-
- theccb->msg_num++;
- theccb->state = SIZE;
- break;
-
- case EXIT:
- if (fd != NULLFILE)
- fclose (fd);
- break;
-
- default:
- break;
- }
- }
-
-
-
- static void
- quit_session (struct pop_ccb *theccb)
- {
- (void) usprintf (theccb->socket, quit_cmd);
-
- theccb->state = EXIT;
- }
-
- #endif /* POP */
-